package redis

import (
	"encoding/binary"
	"time"
)

// ============================= String 数据结构 ========================= //

// Set 存储 key 对应 value，过期时间 ttl
func (r *RedisDataStruct) Set(key []byte, value []byte, ttl int64) error {
	if len(value) == 0 {
		return nil
	}

	// 编码 value = type(byte) + expire(int64) + payload(value)
	buf := make([]byte, binary.MaxVarintLen64+1)
	buf[0] = String
	var idx int = 1
	var expire int64 = 0
	if ttl != 0 {
		expire = time.Now().Add(time.Duration(ttl * time.Second.Nanoseconds())).UnixNano()
	}
	idx += binary.PutVarint(buf[idx:], expire)

	encValue := make([]byte, idx+len(value))
	copy(encValue[:idx], buf[:idx])
	copy(encValue[idx:], value)

	// 考虑设置过期删除，适配 listkeys 操作，否则可在第一次 Get 数据判断过期后，执行删除
	if ttl != 0 {
		go func() {
			time.Sleep(time.Duration(ttl) * time.Second)
			_ = r.db.Delete(key)
		}()
	}

	// 存入数据
	return r.db.Put(key, encValue)
}

// Get 根据 key 获取数据
func (r *RedisDataStruct) Get(key []byte) ([]byte, error) {
	encValue, err := r.db.Get(key)
	if err != nil {
		return nil, err
	}

	// 解码
	// 获取 type
	dataType := encValue[0]
	if dataType != String {
		return nil, ErrWrongTypeOperation
	}

	// 获取 expire
	var idx int = 1
	expire, n := binary.Varint(encValue[idx:])
	idx += n

	// 判断是否过期
	if expire > 0 && expire <= time.Now().UnixNano() {
		return nil, ErrExpireKey
	}
	return encValue[idx:], nil
}
